package com.aabte.lock.jedis.v3;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;

import java.util.List;

/**
 * 执行Redis事务
 */
public class RedisTransaction {

    private JedisPool jedisPool;
    /**
     * Redis客户端
     */
    private Jedis jedis;
    /**
     * 需要观察的Key，比如Redis中保存着商品的Key
     */
    private String lockKey;
    /**
     * 业务业务集合
     */
    private IRedisTransactionProcess businessLogic;

    public RedisTransaction(JedisPool jedisPool, String lockKey, IRedisTransactionProcess businessLogic) {
        this.jedisPool = jedisPool;
        this.jedis = jedisPool.getResource();
        this.lockKey = lockKey;
        this.businessLogic = businessLogic;
    }

    public void invoke() {
        try {
            while (true) {
                // 监视锁，如果后面事务提交exec时发现监视的键值对发生变化时，事务将被取消
                jedis.watch(lockKey);

                // 取数据操作，比如商品数量不足时，可抛出异常表示执行失败
                if (!businessLogic.invokeBeforeProcess(jedis, lockKey)) {
                    break;
                }

                // 开启事务
                Transaction transaction = jedis.multi();

                // 执行业务逻辑
                businessLogic.invokeProcess(transaction, lockKey);

                // 提交事务
                List<Object> result = transaction.exec();
                if (null == result || result.isEmpty()) {
                    // watch-key被外部修改过，回滚操作
                    businessLogic.rollback(jedis, lockKey);
                } else {
                    // 操作成功后的其它业务操作，比如记录结果
                    businessLogic.invokePostProcess(jedis, lockKey);
                    break;
                }
            }
        } catch (Exception e) {
            // handle exception
        } finally {
            jedis.unwatch();
            jedis.close();
        }
    }

}
